package com.example.redis;

import org.redisson.Redisson;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author LiYuhang
 * @version 0.1
 * @application
 * @Copyright 上海申通快递总部
 * @company STO
 * @Date 2022/3/2 22:13
 */
@RestController
public class IndexController {
    private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private Redisson redisson;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 测试节点挂了哨兵重新选举新的master节点，客户端是否能动态感知到
     * 新的master选举出来后，哨兵会把消息发布出去，客户端实际上是实现了一个消息监听机制，
     * 当哨兵把新master的消息发布出去，客户端会立马感知到新master的信息，从而动态切换访问的masterip
     *
     * @throws InterruptedException
     */
    @RequestMapping("/test_sentinel")
    public void testSentinel() throws InterruptedException {
        int i = 1;
        while (true) {
            try {
                stringRedisTemplate.opsForValue().set("李宇航" + i,i + "");
                System.out.println("设置key：" + "李宇航" + i);
                i++;
                Thread.sleep(1000);
            } catch (Exception e) {
                logger.error("错误：",e);
            }
        }
    }

    @RequestMapping("/redlock")
    public String redlock() {
        String lockKey = "product_001";
        //这里需要自己实例化不同redis实例的redisson客户端连接，这里只是伪代码用一个redisson客户端简化了
        RLock lock1 = redisson.getLock(lockKey);

        String key = "product_count";
        /**
         * 根据多个 RLock 对象构建 RedissonRedLock （最核心的差别就在这里）
         */
        RedissonRedLock redLock = new RedissonRedLock(lock1);
        return getString(key,redLock);
    }

    private String getString(String key,RedissonRedLock redLock) {
        try {
            /**
             * waitTimeout 尝试获取锁的最大等待时间，超过这个值，则认为获取锁失败
             * leaseTime   锁的持有时间,超过这个时间锁会自动失效（值应设置为大于业务处理的时间，确保在锁有效期内业务能处理完）
             */
            if (redLock.tryLock(2L,10L,TimeUnit.SECONDS)) {
                //成功获得锁，在这里处理业务
                Integer count = Integer.valueOf(stringRedisTemplate.opsForValue().get(key));
                if (count > 0) {
                    Integer nowCount = count - 1;
                    logger.info("before:{},after:{}",count,nowCount);
                    stringRedisTemplate.opsForValue().decrement(key);
                    return "end";
                }
                System.out.println(" count =0");
                return "count <0";
            }
            System.out.println(" not have a lock");
            return "not have a lock";
        } catch (Exception e) {
            throw new RuntimeException("lock fail");
        } finally {
            //无论如何, 最后都要解锁
            redLock.unlock();
        }
    }

}
